#!/bin/bash
#
# Build a binary package of joy. Supports deb, osxpkg and rpm.
#

usage() { 
    echo "usage:"
    echo ""
    echo "   $0 [ [ -h ] | [ -v version ] [ -t deb|osxpkg|rpm ] [ -r git-reference ] [ -R release ] [ -s ssl-path ] [ -z compression-type]"
    echo ""
    echo "where the options are as follows"
    echo ""
    echo "   The -h flag prints usage information and exits."
    echo ""
    echo "   The -v flag specifies the version of the package to be built."
    echo "   This flag is MANDATORY and should be in the form of Major.Minor"
    echo ""
    echo "   The -t rpm flag builds a RPM.  The -t deb flag builds a deb."
    echo "   The -t osxpkg flag builds an OS X pkg."
    echo ""
    echo "   The -r git-reference pulls from the specified git-reference instead of master."
    echo ""
    echo "   The -R release specifies number preceding the short git commit to allow for"
    echo "   package upgrades on the same joy version."
    echo ""
    echo "   The -s ssl-path is required when building osxpkg and specifies the"
    echo "   location of the OpenSSL header files."
    echo ""
    echo "   The -z compression-type should be none, gzip or bzip2. Default: gzip"
    echo ""
} 

# set defaults
#
NAME=joy
# Set VERSION to 0.0 as it is checked later on
VERSION=0.0
GITREF=master
COMPRESSION=gzip
CWD="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT=$(dirname "$CWD")
PROGNAME=`basename $0`
# Packages required on build host and requirements for built packages
DEBIAN_PKGS="gcc git libcurl3 libcurl4-openssl-dev libpcap0.8 libpcap-dev \
    libssl1.0.2 libssl-dev make python python-pip ruby ruby-ffi"
DEBIAN_REQS="-d libcurl3 -d libpcap0.8 -d libssl1.0.2 -d logrotate"
UBUNTU_PKGS="gcc git libcurl3 libcurl4-openssl-dev libpcap0.8 libpcap-dev \
    libssl1.0.0 libssl-dev make python python-pip ruby ruby-ffi"
UBUNTU_REQS="-d libcurl3 -d libpcap0.8 -d libssl1.0.0 -d logrotate"
MAC_PKGS="gcc gem git make python ruby"
RPM_PKGS="gcc git libcurl libcurl-devel libpcap libpcap-devel make openssl \
    openssl-devel python python2-pip ruby rubygems"
RPM_REQS="-d libcurl -d libpcap -d logrotate -d openssl -d openssl-libs"
ARCH=`uname -m`

echo
echo BUILD_PKGS
echo --------------------
echo

# check command line arguments, ovveride defaults as appropriate
#
while getopts "ht:s:r:R:z:v:" arg; do
    case $arg in
    h)
        usage
        exit
        ;;
    v)
        echo "-v was triggered with option ${OPTARG}" 
        VERSION=${OPTARG}
        ;;
    z)
        echo "-z was triggered with option ${OPTARG}" 
        COMPRESSION=${OPTARG}
        ;;
    t)
        echo "-t was triggered with option ${OPTARG}" 
        BUILDTYPE=${OPTARG}
        ;;
    s)
        echo "-s was triggered with option ${OPTARG}" 
        SSL_PATH=${OPTARG}
        ;;
    r)
        echo "-r was triggered with option ${OPTARG}" 
        GITREF=${OPTARG}
        ;;
    R)
        echo "-R was triggered with option ${OPTARG}" 
        RELEASE=${OPTARG}
        ;;
    \?)
        echo "error: invalid option -${OPTARG}" 
        usage
        exit 1
        ;;
    :)
        echo "error: option -${OPTARG} requires an argument" 
        usage
        exit 1
        ;;
    esac
done
if [ $(($# + 1)) != "${OPTIND}" ]; then
    echo "error: illegal option"
    usage
    exit 1
fi
# Check to make sure they passed in a VERSION
if [ "$VERSION" == 0.0 ]; then
    echo "-v MAJOR.MINOR must be specified (ie. 1.0)" >&2
    exit 1
fi
if [ -z "$BUILDTYPE" ]; then
    echo "-t deb|osxpkg|rpm must be specified" >&2
    exit 1
fi
if [ "$BUILDTYPE" != "osxpkg" ]; then
    OSREL=`lsb_release -is | tr '[:upper:]' '[:lower:]'`
elif [ "$BUILDTYPE" == "osxpkg" ]; then
    OSXVER=`sw_vers -productVersion | awk -F. '{print $1"."$2}'`
    if [ -z "$SSL_PATH" ]; then
        echo "When building joy on OSX, you must specify the -s ssl-path option"
        echo "with the location of the OpenSSL header files."
        exit 1
    fi
fi
if [ -n "$RELEASE" ]; then
    if [ ${RELEASE} -eq ${RELEASE} ] 2>/dev/null; then
        :
    else
        echo "-R release must be a non-zero integer"
        exit 1
    fi
else
    if [ "$GITREF" != "master" ]; then
        RELEASE=0
    else
        RELEASE=1
    fi
fi
if [ $COMPRESSION != "none" -a $COMPRESSION != "gzip" -a $COMPRESSION != "bzip2" ]; then
    echo "-z compression-type must be none, gzip or bzip2"
    exit 1  
fi

# Compression-specific packages and requirements
#
CONFIGURE_ARGS="--prefix=/usr/local"
if [ $COMPRESSION == "gzip" ]; then
    CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-gzip"
    DEBIAN_PKGS="$DEBIAN_PKGS zlib1g zlib1g-dev"
    DEBIAN_REQS="$DEBIAN_REQS -d zlib1g"
    UBUNTU_PKGS="$UBUNTU_PKGS zlib1g zlib1g-dev"
    UBUNTU_REQS="$UBUNTU_REQS -d zlib1g"
    RPM_PKGS="$RPM_PKGS zlib zlib-devel"
    RPM_REQS="$RPM_REQS -d zlib"
elif [ $COMPRESSION == "bzip2" ]; then
    CONFIGURE_ARGS="$CONFIGURE_ARGS --enable-bzip2"
    DEBIAN_PKGS="$DEBIAN_PKGS libbz2-1.0 libbz2-dev"
    DEBIAN_REQS="$DEBIAN_REQS -d bzip2 -d libbz2-1.0"
    UBUNTU_PKGS="$UBUNTU_PKGS libbz2-1.0 libbz2-dev"
    UBUNTU_REQS="$UBUNTU_REQS -d bzip2 -d libbz2-1.0"
    RPM_PKGS="$RPM_PKGS bzip2-libs bzip2-devel"
    RPM_REQS="$RPM_REQS -d bzip2 -d bzip2-libs"
fi

# Check for build dependencies
#
if [ "$BUILDTYPE" == "deb" ]; then
    if [ "$OSREL" != "ubuntu" -a "$OSREL" != "debian" -a "$OSREL" != "raspbian" ]; then
        echo "You must build a deb on a Debian, Raspbian or Ubuntu system."
        exit 1
    fi
    PKGMISSING=0
    if [ "$OSREL" == "ubuntu" ]; then
        for pkg in $UBUNTU_PKGS; do
            STATUS=`/usr/bin/dpkg-query --show --showformat='${db:Status-Status}\n' ${pkg}`
            if [ "$STATUS" != "installed" ]; then
                PKGMISSING=1
            fi
        done
        if [ "$PKGMISSING" != 0 ]; then
            echo "Please install the missing packages.  All required packages"
            echo "can be installed as follows:"
            echo "apt-get install $UBUNTU_PKGS"
            exit 1
        fi
    elif [ "$OSREL" == "debian" -o "$OSREL" == "raspbian" ]; then
        for pkg in $DEBIAN_PKGS; do
            STATUS=`/usr/bin/dpkg-query --show --showformat='${db:Status-Status}\n' ${pkg}`
            if [ "$STATUS" != "installed" ]; then
                PKGMISSING=1
            fi
        done
        if [ "$PKGMISSING" != 0 ]; then
            echo "Please install the missing packages.  All required packages"
            echo "can be installed as follows:"
            echo "apt-get install $DEBIAN_PKGS"
            exit 1
        fi
    fi

elif [ "$BUILDTYPE" == "osxpkg" ]; then
    PKGMISSING=0
    for pkg in $MAC_PKGS; do
        if [ ! -x /usr/bin/$pkg ]; then
            echo "You must have $pkg installed to build an OS X package."
            PKGMISSING=1
        fi
    done
    if [ "$PKGMISSING" != 0 ]; then
        echo "Please install the missing packages.  All required packages"
        echo "can be installed as follows:"
        echo "xcode-select --install"
        exit 1
    fi
elif [ "$BUILDTYPE" == "rpm" ]; then
    if [ ! -f /etc/redhat-release ]; then
        echo "You must build an RPM on a Red Hat or CentOS system."
        exit 1
    fi
    PKGMISSING=0
    for pkg in $RPM_PKGS; do
        STATUS=`rpm -q --qf '%{name}' ${pkg}.${ARCH}`
        if [ "$STATUS" != "$pkg" ]; then
            STATUS=`rpm -q --qf '%{name}' ${pkg}.noarch`
            if [ "$STATUS" != "$pkg" ]; then
                echo "$STATUS"
                PKGMISSING=1
            fi
        fi
    done
    if [ "$PKGMISSING" != 0 ]; then
        echo "Please install the missing packages.  All required packages"
        echo "can be installed as follows:"
        echo "yum install $RPM_PKGS"
        exit 1
    fi
else
    echo "Unsupported build type $BUILDTYPE"
    usage
    exit 1
fi
if [ ! -x "/usr/local/bin/fpm" -a ! -x "/opt/local/bin/fpm" ]; then
    echo "You must install fpm before proceeding."
    echo "Run 'gem install fpm'"
    exit 1
fi

COMMIT_ID=$(git show-ref --hash refs/heads/$GITREF)
if [ -z "$COMMIT_ID" ]; then
    echo "Unable to find git reference $GITREF. Please enter a valid reference."
    exit 1
fi
SHORT_COMMIT_ID=$(git show-ref --hash=7 refs/heads/$GITREF)
ITERATION="${RELEASE}.${SHORT_COMMIT_ID}"
if [ "$OSREL" == "debian" -o "$OSREL" == "ubuntu" ]; then
    CODENAME=`lsb_release -cs`
    ITERATION="$ITERATION.$CODENAME"
elif [ -n "$OSXVER" ]; then
    ITERATION="$ITERATION.macosx.$OSXVER"
fi
FULL_VERSION="${VERSION}-${ITERATION}"
TAR_FILE=`pwd`/joy-$SHORT_COMMIT_ID.tar
TMPDIR=`mktemp -d /var/tmp/${PROGNAME}.XXXXXX`
BUILDROOT="${TMPDIR}/build"
if [ "$?" != 0 ]; then
    echo Failed to create temp directory $TMPDIR
    exit 1
fi
FPM_LINUX_OPTIONS="-C $BUILDROOT -n $NAME -v $VERSION --iteration $ITERATION \
    --after-install $APP_ROOT/joy/install_joy/postinstall-linux \
    --before-install $APP_ROOT/joy/install_joy/preinstall-linux \
    --after-remove $APP_ROOT/joy/install_joy/postuninstall-linux \
    --before-remove $APP_ROOT/joy/install_joy/preuninstall-linux \
    --vendor Cisco --config-files /usr/local/etc/joy/ \
    --config-files /usr/local/var/joy \
    --config-files /usr/local/var/log \
    -m brilong@cisco.com -p $APP_ROOT \
    --url https://github.com/cisco/joy"
FPM_MAC_OPTIONS="-C $BUILDROOT -n $NAME -v $VERSION-$ITERATION \
    --after-install $APP_ROOT/joy/install_joy/postinstall-darwin \
    --before-install $APP_ROOT/joy/install_joy/preinstall-darwin \
    --vendor Cisco \
    --osxpkg-identifier-prefix com.cisco \
    --osxpkg-dont-obsolete /usr/local/etc/joy/ \
    --osxpkg-dont-obsolete /usr/local/var/joy \
    --osxpkg-dont-obsolete /usr/local/var/log \
    -m brilong@cisco.com -p $APP_ROOT \
    --url https://github.com/cisco/joy"

git archive --format=tar --prefix="joy/" $COMMIT_ID > $TAR_FILE
if [ "$?" != 0 ]; then
    echo Failed to create git archive tar
    rmdir $TMPDIR
    exit 1
fi
# Used for pkg development; grab files not yet checked-in to master
if [ "$GITREF" != "master" ]; then
    tar -f $TAR_FILE --delete joy/install_joy/install-sh 2>/dev/null
    tar -rvf $TAR_FILE -C .. joy/src/joy.c joy/install_joy/install-sh joy/install_joy/postinstall-darwin joy/install_joy/preinstall-darwin
    if [ "$?" != 0 ]; then
        echo Failed to update archive tar
        rmdir $TMPDIR
        exit 1
    fi
fi
cd $TMPDIR
if [ "$?" != 0 ]; then
    echo Failed to change to $TMPDIR
    rmdir $TMPDIR
    exit 1
fi
tar xf $TAR_FILE || exit 1
if [ "$?" != 0 ]; then
    echo Failed to untar $TAR_FILE
    exit 1
fi
cd $NAME
if [ "$?" != 0 ]; then
    echo Failed to change directory to $NAME
    exit 1
fi
if [ "$BUILDTYPE" == "deb" ]; then
    if [ "$ARCH" == "x86_64" ]; then
        #./configure $CONFIGURE_ARGS -l /usr/lib/x86_64-linux-gnu
        ./configure $CONFIGURE_ARGS
    elif [ "$ARCH" == "armv7l" ]; then
        #./configure $CONFIGURE_ARGS -l /usr/lib/arm-linux-gnueabihf
        ./configure $CONFIGURE_ARGS
    else
        echo "Arch $ARCH not supported"
        exit 1
    fi
elif [ "$BUILDTYPE" == "osxpkg" ]; then
    ./configure $CONFIGURE_ARGS  --with-ssl-dir=$SSL_PATH
elif [ "$BUILDTYPE" == "rpm" ]; then
    #./configure $CONFIGURE_ARGS -l /usr/lib64
    echo Running ./configure $CONFIGURE_ARGS
    ./configure $CONFIGURE_ARGS
fi
if [ "$?" != 0 ]; then
    echo Failed to run ./configure
    exit 1
fi
echo "$FULL_VERSION" > VERSION
make clean; make
if [ "$?" != 0 ]; then
    echo Failed to run make
    exit 1
fi
make DESTDIR=${BUILDROOT} BUILDROOT=${BUILDROOT} install
if [ "$?" != 0 ]; then
    echo Failed to run make install
    exit 1
fi

#strip -s ${TMPDIR}/usr/local/bin/joy

if [ "$BUILDTYPE" == "deb" ]; then
    if [ "$OSREL" == "ubuntu" ]; then
        FPM_REQS="$UBUNTU_REQS"
    elif [ "$OSREL" == "debian" ]; then
        FPM_REQS="$DEBIAN_REQS"
    fi
    fpm -s dir -t deb $FPM_LINUX_OPTIONS $FPM_REQS \
        -d "python >= 2.7" \
        --deb-no-default-config-files \
        --description "Joy is a libpcap-based software package for extracting data features from live
network traffic or packet capture \(pcap\) files, using a flow-oriented model
similar to that of IPFIX or Netflow, and then representing these data features
in JSON. It also contains analysis tools that can be applied to these data
files. Joy can be used to explore data at scale, especially security and
threat-relevant data. (Compression: $COMPRESSION)" \
        ./
    if [ "$?" != 0 ]; then
        echo Failed to build deb
        exit 1
    fi
elif [ "$BUILDTYPE" == "osxpkg" ]; then
    fpm -s dir -t osxpkg $FPM_MAC_OPTIONS \
        --description "Joy is a libpcap-based software package for extracting data features from live
network traffic or packet capture \(pcap\) files, using a flow-oriented model
similar to that of IPFIX or Netflow, and then representing these data features
in JSON. It also contains analysis tools that can be applied to these data
files. Joy can be used to explore data at scale, especially security and
threat-relevant data. (Compression: $COMPRESSION)" \
        ./
    if [ "$?" != 0 ]; then
        echo Failed to build OS X pkg
        exit 1
    fi
elif [ "$BUILDTYPE" == "rpm" ]; then
    if [ "$OSREL" == "centos" -o "$OSREL" == "redhatenterpriseserver" ]; then
        FPM_REQS="$RPM_REQS"
    else
        echo Unable to build rpm on $OSREL
        exit 1
    fi
    fpm -s dir -t rpm $FPM_LINUX_OPTIONS $FPM_REQS \
        -d "kernel >= 3.10" -d "python >= 2.7" \
        --config-files /etc/systemd/system/joy.service.d/20-accounting.conf \
        --description 'Joy is a libpcap-based software package for extracting data features from live
network traffic or packet capture (pcap) files, using a flow-oriented model
similar to that of IPFIX or Netflow, and then representing these data features
in JSON. It also contains analysis tools that can be applied to these data
files. Joy can be used to explore data at scale, especially security and
threat-relevant data.' \
        --rpm-dist el7 \
        --rpm-summary "Capture and analyze network flow data for research, forensics and monitoring. (Compression: $COMPRESSION)" \
        --rpm-attr 775,joy,joy:/usr/local/var/joy \
        --rpm-attr 775,joy,joy:/usr/local/var/log \
        ./
    if [ "$?" != 0 ]; then
        echo Failed to build RPM
        exit 1
    fi
fi
rm -f $TAR_FILE
rm -rf $TMPDIR
